﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqToDB.Provider
{
    class SqlNodePrinter
    {
        int space = 0;
        void Begin(string name, object value)
        {
            for (int i = 0; i < space; i++)
            {
                Console.Write("  ");
            }
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.Write("{0} ", name);
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("{0} ", value);
            space++;
        }
        void End(string name, object value)
        {
            space--;
        }

        public SqlNode Visit(SqlNode node)
        {
            if (node == null)
                return null;
            switch (node.NodeType)
            {
                case SqlNodeType.Default:
                    return VisitDefault((SqlDefault)node);
                case SqlNodeType.Negate:
                case SqlNodeType.Not:
                case SqlNodeType.Convert:
                    return this.VisitUnary((SqlUnary)node);
                case SqlNodeType.Add:
                case SqlNodeType.Subtract:
                case SqlNodeType.Multiply:
                case SqlNodeType.Divide:
                case SqlNodeType.Modulo:
                case SqlNodeType.And:
                case SqlNodeType.Or:
                case SqlNodeType.LessThan:
                case SqlNodeType.LessThanOrEqual:
                case SqlNodeType.GreaterThan:
                case SqlNodeType.GreaterThanOrEqual:
                case SqlNodeType.Equal:
                case SqlNodeType.NotEqual:
                    return this.VisitBinary((SqlBinary)node);
                case SqlNodeType.Lambda:
                    return this.VisitLambda((SqlLambda)node);
                case SqlNodeType.Select:
                    return this.VisitSelect((SqlSelect)node);
                case SqlNodeType.SelectMany:
                    return this.VisitSelectMany((SqlSelectMany)node);
                case SqlNodeType.Where:
                    return this.VisitWhere((SqlWhere)node);
                case SqlNodeType.Table:
                    return this.VisitTable((SqlTable)node);
                case SqlNodeType.Alias:
                    return this.VisitAlias((SqlAlias)node);
                case SqlNodeType.AliasRef:
                    return this.VisitAliasRef((SqlAliasRef)node);
                case SqlNodeType.Member:
                    return this.VisitMember((SqlMember)node);
                case SqlNodeType.Method:
                    return this.VisitMethod((SqlMethod)node);
                case SqlNodeType.Value:
                    return this.VisitValue((SqlValue)node);
                case SqlNodeType.Row:
                    return this.VisitRow((SqlRow)node);
            }
            throw new Exception(string.Format("未处理的表达式类型！{0}", node.NodeType));
        }

        private SqlNode VisitRow(SqlRow sqlRow)
        {
            Begin("Row", null);
            foreach (var item in sqlRow.Items)
                Visit(item);
            End("Row", null);
            return sqlRow;
        }

        private SqlNode VisitValue(SqlValue sqlValue)
        {
            Begin("Value", sqlValue.Value);
            End("Value", null);
            return sqlValue;
        }

        private SqlNode VisitLambda(SqlLambda sqlLambda)
        {
            Begin("Lambda", null);
            Visit(sqlLambda.Body);
            End("Lambda", null);
            return sqlLambda;
        }

        private SqlNode VisitSelect(SqlSelect sqlSelect)
        {
            Begin("Select", null);
            Visit(sqlSelect.From);
            Visit(sqlSelect.Row);
            End("Select", null);
            return sqlSelect;
        }

        private SqlNode VisitSelectMany(SqlSelectMany sqlSelectMany)
        {
            Begin("SelectMany", null);
            Visit(sqlSelectMany.From1);
            Visit(sqlSelectMany.From2);
            Visit(sqlSelectMany.Row);
            End("SelectMany", null);
            return sqlSelectMany;
        }

        private SqlNode VisitWhere(SqlWhere sqlWhere)
        {
            Begin("Where", null);
            Visit(sqlWhere.From);
            Visit(sqlWhere.Condition);
            End("Where", null);
            return sqlWhere;
        }

        private SqlNode VisitTable(SqlTable sqlTable)
        {
            Begin("Table", sqlTable.Table.TableName);
            End("Table", null);
            return sqlTable;
        }

        private SqlNode VisitAlias(SqlAlias sqlAlias)
        {
            Begin("Alias", sqlAlias.Alias);
            Visit(sqlAlias.Source);
            End("Alias", null);
            return sqlAlias;
        }

        private SqlNode VisitAliasRef(SqlAliasRef sqlAliasRef)
        {
            Begin("AliasRef", sqlAliasRef.Alias);
            End("AliasRef", null);
            return sqlAliasRef;
        }

        private SqlNode VisitMethod(SqlMethod sqlMethod)
        {
            Begin("Method", sqlMethod.Method);
            foreach (var item in sqlMethod.Arguments)
                Visit(item);
            End("Method", null);
            return sqlMethod;
        }

        private SqlNode VisitMember(SqlMember sqlMember)
        {
            Begin("Member", sqlMember.Member);
            Visit(sqlMember.Object);
            End("Member", null);
            return sqlMember;
        }

        private SqlNode VisitBinary(SqlBinary sqlBinary)
        {
            Begin(sqlBinary.NodeType.ToString(), null);
            Visit(sqlBinary.Left);
            Visit(sqlBinary.Right);
            End(sqlBinary.NodeType.ToString(), null);
            return sqlBinary;
        }

        private SqlNode VisitUnary(SqlUnary sqlUnary)
        {
            Begin(sqlUnary.NodeType.ToString(), null);
            Visit(sqlUnary.Value);
            End(sqlUnary.NodeType.ToString(), null);
            return sqlUnary;
        }

        private SqlNode VisitDefault(SqlDefault sqlDefault)
        {
            Begin(sqlDefault.Command, sqlDefault.Value);
            foreach (var item in sqlDefault.SubNodes)
                Visit(item);
            End(sqlDefault.Command, sqlDefault.Value);
            return sqlDefault;
        }

    }
}
